import asyncio
import os
import time
import json
from datetime import datetime
from fastapi import APIRouter, Query, HTTPException
from starlette.responses import JSONResponse
import requests
from typing import Dict, List, Optional, Any

# 创建系统监控的路由
system_router = APIRouter()

# 从utils.py导入配置信息
import utils
CONFIG = utils.CONFIG

# 根据nodeid获取节点信息
def getnodeip(nodeid: str) -> Optional[Dict[str, Any]]:   
    for node in CONFIG["edgesrv_list"]:
        if str(node["id"]) == nodeid:
            return node
    return None

# edgesrv状态信息存储
system_status: Dict[int, Dict] = {}

# 上次更新时间
last_update_time: float = 0

# 更新间隔（秒）
UPDATE_INTERVAL = 60  # 每分钟更新一次

# 监控任务标志
monitoring_task_running = False

# 监控任务
async def monitor_edgesrv():
    """定时监控所有edgesrv节点的状态"""
    global monitoring_task_running, last_update_time
    monitoring_task_running = True
    
    while True:
        try:
            await update_edgesrv_status()
            last_update_time = time.time()
        except Exception as e:
            print(f"监控任务执行失败: {e}")
        
        # 等待下一次更新
        await asyncio.sleep(UPDATE_INTERVAL)

async def update_edgesrv_status():
    """更新所有edgesrv节点的状态信息"""
    for edge_node in CONFIG["edgesrv_list"]:
        node_id = edge_node["id"]
        ip = edge_node["ip"]
        port = edge_node["port"]
        path = edge_node["path"]
        
        try:
            # 获取edgesrv状态信息
            status_info = await get_edgesrv_status(ip, port, path)
            system_status[node_id] = status_info
            print(f"成功更新edgesrv {node_id} 状态")
        except Exception as e:
            print(f"更新edgesrv {node_id} 状态失败: {e}")
            # 标记为离线
            if node_id in system_status:
                system_status[node_id]["online"] = False
                system_status[node_id]["last_error"] = str(e)
                system_status[node_id]["last_update"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            else:
                system_status[node_id] = {
                    "id": node_id,
                    "ip": ip,
                    "port": port,
                    "path": path,
                    "online": False,
                    "last_error": str(e),
                    "last_update": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                }

async def get_edgesrv_status(ip: str, port: int, path: str) -> Dict:
    """获取单个edgesrv节点的状态信息"""
    status_info = {
        "id": None,
        "ip": ip,
        "port": port,
        "path": path,
        "online": False,
        "disk_space": {
            "total": 0,
            "used": 0,
            "free": 0,
            "percent": 0
        },
        "load": {
            "cpu": 0,
            "memory": 0
        },
        "file_count": 0,
        "last_update": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    
    try:
        # 尝试通过HTTP请求获取状态信息
        url = f"http://{ip}:{port}/api/status"
        response = await asyncio.to_thread(requests.get, url, timeout=5)
        
        if response.status_code == 200:
            data = response.json()
            status_info.update(data)
            status_info["online"] = True
        else:
            print(f"edgesrv {ip}:{port} 状态请求返回非200状态码: {response.status_code}")
    except requests.exceptions.RequestException as e:
        # 如果HTTP请求失败，尝试本地获取磁盘信息（如果路径可访问）
        print(f"edgesrv {ip}:{port} HTTP请求失败，尝试本地获取磁盘信息: {e}")
        try:
            # 尝试获取磁盘空间信息
            if os.path.exists(path):
                total, used, free = get_disk_space(path)
                status_info["disk_space"] = {
                    "total": total,
                    "used": used,
                    "free": free,
                    "percent": (used / total) * 100 if total > 0 else 0
                }
                
                # 计算文件数量
                file_count = get_file_count(path)
                status_info["file_count"] = file_count
                
                # 标记为半在线（本地可访问，但API不可用）
                status_info["online"] = True
                status_info["api_status"] = "unavailable"
        except Exception as inner_e:
            print(f"本地获取edgesrv {ip}:{port} 信息失败: {inner_e}")
    
    return status_info

def get_disk_space(path: str) -> tuple:
    """获取指定路径的磁盘空间信息"""
    try:
        # Windows系统使用winshell获取磁盘信息
        if os.name == 'nt':
            import wmi
            c = wmi.WMI()
            # 获取路径所在的驱动器
            drive = os.path.splitdrive(path)[0]
            for disk in c.Win32_LogicalDisk(DriveLetter=drive):
                total = int(disk.Size) if disk.Size else 0
                free = int(disk.FreeSpace) if disk.FreeSpace else 0
                used = total - free
                return total, used, free
        # Linux/Unix系统使用os.statvfs
        else:
            statvfs = os.statvfs(path)
            total = statvfs.f_frsize * statvfs.f_blocks
            free = statvfs.f_frsize * statvfs.f_bfree
            used = total - free
            return total, used, free
    except Exception as e:
        print(f"获取磁盘空间失败: {e}")
        return 0, 0, 0

def get_file_count(path: str) -> int:
    """获取指定路径下的文件总数"""
    count = 0
    try:
        for _, _, files in os.walk(path):
            count += len(files)
    except Exception as e:
        print(f"获取文件数量失败: {e}")
    return count

# 启动监控任务
async def start_monitoring():
    """启动edgesrv监控任务"""
    global monitoring_task_running
    if not monitoring_task_running:
        asyncio.create_task(monitor_edgesrv())

# 系统接口

@system_router.get("/v1/system/edgesrv/status")
async def get_edgesrv_status_all(
    node_id: Optional[int] = Query(None, description="指定节点ID，不指定则返回所有节点状态")
):
    """获取edgesrv节点的状态信息"""
    # 如果监控任务未启动，启动它
    await start_monitoring()
    
    # 如果是首次请求或长时间未更新，立即更新一次
    global last_update_time
    if time.time() - last_update_time > UPDATE_INTERVAL or not system_status:
        await update_edgesrv_status()
        last_update_time = time.time()
    
    if node_id is not None:
        if node_id in system_status:
            return JSONResponse(content={"code": 200, "data": system_status[node_id]})
        else:
            return JSONResponse(content={"code": 404, "msg": "节点不存在"})
    else:
        return JSONResponse(content={"code": 200, "data": list(system_status.values())})

@system_router.get("/v1/system/edgesrv/disk")
async def get_edgesrv_disk_space(
    node_id: Optional[int] = Query(None, description="指定节点ID，不指定则返回所有节点磁盘信息")
):
    """获取edgesrv节点的磁盘空间信息"""
    await start_monitoring()
    
    if time.time() - last_update_time > UPDATE_INTERVAL or not system_status:
        await update_edgesrv_status()
        last_update_time = time.time()
    
    disk_info = {}
    if node_id is not None:
        if node_id in system_status:
            disk_info[node_id] = system_status[node_id].get("disk_space", {})
            disk_info[node_id]["online"] = system_status[node_id].get("online", False)
            disk_info[node_id]["last_update"] = system_status[node_id].get("last_update", "")
        else:
            return JSONResponse(content={"code": 404, "msg": "节点不存在"})
    else:
        for nid, status in system_status.items():
            disk_info[nid] = status.get("disk_space", {})
            disk_info[nid]["online"] = status.get("online", False)
            disk_info[nid]["last_update"] = status.get("last_update", "")
    
    return JSONResponse(content={"code": 200, "data": disk_info})

@system_router.get("/v1/system/edgesrv/load")
async def get_edgesrv_load(
    node_id: Optional[int] = Query(None, description="指定节点ID，不指定则返回所有节点负载信息")
):
    """获取edgesrv节点的负载信息"""
    await start_monitoring()
    
    if time.time() - last_update_time > UPDATE_INTERVAL or not system_status:
        await update_edgesrv_status()
        last_update_time = time.time()
    
    load_info = {}
    if node_id is not None:
        if node_id in system_status:
            load_info[node_id] = system_status[node_id].get("load", {})
            load_info[node_id]["online"] = system_status[node_id].get("online", False)
            load_info[node_id]["last_update"] = system_status[node_id].get("last_update", "")
        else:
            return JSONResponse(content={"code": 404, "msg": "节点不存在"})
    else:
        for nid, status in system_status.items():
            load_info[nid] = status.get("load", {})
            load_info[nid]["online"] = status.get("online", False)
            load_info[nid]["last_update"] = status.get("last_update", "")
    
    return JSONResponse(content={"code": 200, "data": load_info})

@system_router.get("/v1/system/health")
async def system_health_check():
    """系统健康检查"""
    # 检查数据库连接
    from .utils import nas_sqlite_dirdb_get,get_mysql_conn    
    
    mysql_connected = False
    try:
        mysql_conn = get_mysql_conn()
        if mysql_conn:
            mysql_connected = True
            mysql_conn.close()
    except Exception:
        pass
    
    sqlite_connected = False
    try:
        # 尝试连接一个示例的SQLite数据库
        sqlite_conn = nas_sqlite_dirdb_get("test", "/test")
        if sqlite_conn:
            sqlite_connected = True
            sqlite_conn.close()
    except Exception:
        pass
    
    # 检查edgesrv监控状态
    edgesrv_monitored = len(system_status) > 0
    
    # 综合健康状态
    overall_health = mysql_connected and sqlite_connected
    
    return JSONResponse(content={
        "code": 200,
        "status": "ok" if overall_health else "warning",
        "components": {
            "mysql": "connected" if mysql_connected else "disconnected",
            "sqlite": "connected" if sqlite_connected else "disconnected",
            "edgesrv_monitor": "active" if edgesrv_monitored else "inactive",
            "edgesrv_count": len(CONFIG["edgesrv_list"]),
            "monitored_count": len(system_status),
            "last_update_time": datetime.fromtimestamp(last_update_time).strftime("%Y-%m-%d %H:%M:%S") if last_update_time > 0 else "never"
        }
    })